package cn.ipanel.bigdata.boot.config

import org.yaml.snakeyaml.Yaml
import org.yaml.snakeyaml.constructor.{Constructor, CustomClassLoaderConstructor}

import scala.collection.mutable

/**
 * Author: lzz
 * Date: 2021/11/16 16:15
 */
object Configuration {

  // 项目默认使用的配置文件
  private[boot] val filename: String = "application.yaml"
  // 组装后的配置
  private[boot] lazy val config: Config = load

  // 任何类型的db，放一个map里面
  private[boot] lazy val dbMap: mutable.HashMap[String, Database] = {
    val map = new mutable.HashMap[String, Database]()
    import scala.collection.JavaConversions._
    for (db <- config.source.database) {
      map.put(db.getName, db)
    }
    map
  }

  // 任何类型的protocol，放一个map里面
  private[boot] lazy val ptMap: mutable.HashMap[String, Protocol] = {
    val map = new mutable.HashMap[String, Protocol]()
    import scala.collection.JavaConversions._
    for (pt <- config.source.protocol) {
      map.put(pt.name, pt)
    }
    map
  }

  // 任何类型的hdfs，放一个map里面，不过没用到
  private[boot] lazy val fdMap: mutable.HashMap[String, Hdfs] = {
    val map = new mutable.HashMap[String, Hdfs]()
    import scala.collection.JavaConversions._
    for (pt <- config.hadoop.hdfs) {
      map.put(pt.genre, pt)
    }
    map
  }

  // 任何类型的template，放一个map里面，不过没用到
  private[boot] lazy val templateMap: mutable.HashMap[String, Template] = {
    val map = new mutable.HashMap[String, Template]()
    import scala.collection.JavaConversions._
    if (null != Configuration.config.project.template) {
      for (t <- Configuration.config.project.template) {
        map.put(t.job, t)
      }
    }
    map
  }

  // 对外依赖的任何类型的table alias 跟物理表名和数据库名的映射关系，放一个map里面
  private[boot] lazy val tableMap: mutable.HashMap[String, Table] = {
    val map = new mutable.HashMap[String, Table]()
    import scala.collection.JavaConversions._
    if (null != Configuration.config.source.table) {
      for (t <- Configuration.config.source.table) {
        map.put(t.alias, t)
      }
    }
    map
  }

  private[this] def load: Config = {
    val stream = getClass.getClassLoader.getResourceAsStream(filename)
    val config = new Yaml(new Constructor(classOf[Config])).load(stream).asInstanceOf[Config]
    import scala.collection.JavaConversions._
    for (kv <- config.properties.conf) {
      System.setProperty(kv._1, kv._2)
    }
    config
  }

  def source: Source = if (config == null) null else config.getSource
  def spark: Spark = if (config == null) null else config.getSpark
  def hadoop: Hadoop = if (config == null) null else config.getHadoop

  def getDatabase(name: String): Database = if (dbMap.contains(name)) dbMap(name) else null
  def getProtocol(name: String): Protocol = if (ptMap.contains(name)) ptMap(name) else null
  def getHdfsPath(genre: String): Hdfs = if (fdMap.contains(genre)) fdMap(genre) else null
  def getProjectName(): String = config.getProject.name
  def getTemplate(jobName: String): Template = {
    if (templateMap.contains(jobName)) templateMap(jobName)
    else {
      val template: Template = new Template
      template.job = jobName
      template
    }
  }

  def getParam(name: String): String = if (config == null) null else config.getProperties.param.get(name)
  def getParam(name: String, defV: String): String = {
    val v = getParam(name)
    if (v == null) {
      defV
    } else v
  }

  def getProperty(name: String): String = if (config == null) null else config.getProperties.conf.get(name)
  // 必须要加 contains 判断，或使用getOrElse(alias, defValue)的方式，否则对没有的 key会报 NoSuchElementException: key not found: keyName
  def getTableInfo(alias: String): Table = tableMap.getOrElse(alias, null)

  def getParamOrElse[K](key: String, defV: K): K = {
    val v = getParam(key)
    if (v != null && !v.trim.equals("")) {
      (defV match {
        case _: Double => v.toDouble
        case _: Float => v.toFloat
        case _: Int => v.toInt
        case _: Boolean => v.toBoolean
        case _: Long => v.toLong
        case _ => v
      }).asInstanceOf[K]
    } else {
      defV
    }
  }
}